package logic

import (
	"core/command"
	"core/component/function"
	"core/component/logger"
	"core/component/router"
	"runtime/debug"
)

type Player struct {
	router          *router.Router
	innerRouter     *router.Router
	roomId          uint64
	playerId        uint64
	score           Score       //所属分段
	poolMapKey      int32       //所属匹配池
	innerMsgChannel chan []byte //玩家消息通道
	chanPlayerData  chan []byte
	chanOffline     chan int //退出pvp信号
	joinPvpPoolTime int64    //进入pvp池时间
	nickName        string
	onlineSrvID     string //玩家所在online服务器ID
	isGaming        bool
	isInitFinish    bool
	isOffline       bool
}

type TempPlayer struct {
	p       *Player
	isRobot bool
}

func newPlayer(pInfo *command.PlayerIntoPvpServer) *Player {
	p := &Player{
		router:          router.NewRouter(),
		innerRouter:     router.NewRouter(),
		playerId:        pInfo.PlayerId,
		onlineSrvID:     pInfo.OnlineSrvID,
		innerMsgChannel: make(chan []byte, 1024),
		chanOffline:     make(chan int, 1),
		chanPlayerData:  make(chan []byte, 1024),
		nickName:        pInfo.NickName,
	}
	p.registerMsgHandler()
	p.registerInnerMsgHandler()
	go p.loop()
	return p
}

func (player *Player) addPlayerMsgChannel(data []byte) {
	player.chanPlayerData <- data
}

func (player *Player) setPlayerPoolKey(poolKey int32) {
	player.poolMapKey = poolKey
}

func (player *Player) loop() {
	if !player.isInitFinish {
		player.isInitFinish = true
	}
	defer func() {
		if err := recover(); err != nil {
			function.WritePanic(string(debug.Stack()), err)
			if player.isInitFinish && !player.isOffline {
				go player.loop()
				return
			}
			player.offline()
		}
	}()
	for {
		select {
		case data := <-player.chanPlayerData:
			player.onMessage(data)
		case <-player.chanOffline:
			player.isOffline = true
			player.offline()
			logger.Infof("玩家(%v)退出pvp", player.playerId)
			return
		case data := <-player.innerMsgChannel:
			player.handleSyncMsg(data)
		}
	}
}

func (player *Player) handleSyncMsg(data []byte) {
	msgID, err := player.innerRouter.Route(data)
	if err != nil {
		logger.Errorf("[route] 路由内部消息失败 msgID:%v, err:%v", msgID, err)
	}
}

func (player *Player) sendToPlayerGoroutine(cmd command.Command, msg interface{}) {
	data, err := player.innerRouter.Marshal(uint16(cmd), msg)
	if err != nil {
		return
	}
	player.innerMsgChannel <- data
}

func (player *Player) onMessage(data []byte) {
	_, err := player.router.Route(data)
	if err != nil {
		return
	}
}

// 取消匹配
func (player *Player) cancelPvp() {
	pl, ok := WorldGetMe().pvps.pools[player.score]
	if !ok {
		return
	}
	player.isGaming = false
	pl.removePvpPool(player)
	msgSend := &command.SCCancelPvp{}
	player.SendMsgToClient(command.Command_SCCancelPvp_Pvp, msgSend)
}

// 发送数据给online服的玩家
func (player *Player) sendMsgToOnlinePlayer(cmd command.Command, msg interface{}) bool {
	// Marshal 返回的数据包括 flag|cmd|pbdata
	data, err := player.router.Marshal(uint16(cmd), msg)
	if err != nil {
		logger.Errorf("send msg to client error msg id %v playerID:%v", cmd, player.playerId)
		return false
	}
	sendMsg := &command.SrvMsgToOnlinePlayer{Playerid: player.playerId, Data: data[2:]}
	return onlineServerMgrGetMe().sendMsgToOnlineServer(player.onlineSrvID, command.Command_SrvMsgToOnlinePlayer_Server, sendMsg)
}

// SendMsgToClient 发送数据给客户端
func (player *Player) SendMsgToClient(cmd command.Command, msg interface{}) bool {
	return onlineServerMgrGetMe().sendMsgToOnlinePlayer(player.onlineSrvID, player.playerId, cmd, msg)
}

func (player *Player) offline() {
	WorldGetMe().sendRemovePlayer(player.playerId)

	player.offlineClear()
	logger.Infof("玩家(%v)下线", player.playerId)
}

func (player *Player) handleOfflineOP() {
	if player.isOffline {
		return
	}
	// 玩家已经开始离线操作了
	player.chanOffline <- 1
}

func (player *Player) offlineClear() {
	close(player.chanPlayerData)
	close(player.innerMsgChannel)
	close(player.chanOffline)
	player.router.Clear()
	player.router = nil
	player.innerRouter.Clear()
	player.innerRouter = nil
}

func (player *Player) exitRoom() {
	player.roomId = 0
	player.poolMapKey = 0
	player.score = 0
	player.isGaming = false
}
